package com.chuanyun.wechatcheckin.service;

import com.chuanyun.wechatcheckin.GeoUtils;
import com.chuanyun.wechatcheckin.model.h3yun.H3yunResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 项目地理位置服务
 * 负责查询氚云项目表数据，提供地理位置匹配功能
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProjectLocationService {

    private final H3yunApiService h3yunApiService;
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    // 项目表的schemaCode
    private static final String PROJECT_SCHEMA_CODE = "sclp7hggqq0aad1ncyzf";
    
    // 项目名称字段
    private static final String PROJECT_NAME_FIELD = "F0000001";
    
    // 项目经纬度字段
    private static final String PROJECT_LOCATION_FIELD = "F0000026";
    
    // 距离阈值（米）
    private static final double DISTANCE_THRESHOLD = 1000.0;
    
    /**
     * 项目位置信息
     */
    public static class ProjectLocation {
        private String projectName;
        private double latitude;
        private double longitude;
        
        public ProjectLocation(String projectName, double latitude, double longitude) {
            this.projectName = projectName;
            this.latitude = latitude;
            this.longitude = longitude;
        }
        
        public String getProjectName() { return projectName; }
        public double getLatitude() { return latitude; }
        public double getLongitude() { return longitude; }
    }
    
    /**
     * 查询所有项目的地理位置信息
     * @return 项目位置信息列表
     */
    public List<ProjectLocation> getAllProjectLocations() throws Exception {
        log.info("开始查询氚云项目表地理位置数据，SchemaCode: {}", PROJECT_SCHEMA_CODE);
        
        List<ProjectLocation> projectLocations = new ArrayList<>();
        List<String> returnItems = Arrays.asList(PROJECT_NAME_FIELD, PROJECT_LOCATION_FIELD);
        
        // 分页查询所有项目数据
        int pageSize = 1000;
        int currentOffset = 0;
        boolean hasMoreData = true;
        
        while (hasMoreData) {
            H3yunResponse<Object> response = h3yunApiService.queryBizDataWithConditions(
                PROJECT_SCHEMA_CODE, currentOffset, currentOffset + pageSize, returnItems, null);
            
            if (!response.isSuccess()) {
                log.error("查询氚云项目数据失败: {}", response.getErrorMessage());
                throw new RuntimeException("查询氚云项目数据失败: " + response.getErrorMessage());
            }
            
            List<Map<String, Object>> records = parseResponseData(response.getReturnData());
            
            if (records.isEmpty()) {
                hasMoreData = false;
                log.info("第 {} 页无数据，查询结束", (currentOffset / pageSize) + 1);
            } else {
                // 解析项目位置信息
                for (Map<String, Object> record : records) {
                    ProjectLocation location = parseProjectLocation(record);
                    if (location != null) {
                        projectLocations.add(location);
                    }
                }
                
                log.info("第 {} 页查询到 {} 条记录，解析出 {} 个有效项目位置", 
                        (currentOffset / pageSize) + 1, records.size(), projectLocations.size());
                
                if (records.size() < pageSize) {
                    hasMoreData = false;
                } else {
                    currentOffset += pageSize;
                }
            }
        }
        
        log.info("项目地理位置数据查询完成，共获取 {} 个项目位置", projectLocations.size());
        return projectLocations;
    }
    
    /**
     * 根据打卡经纬度匹配最近的项目
     * @param checkinLat 打卡纬度（实际纬度的1000000倍）
     * @param checkinLng 打卡经度（实际经度的1000000倍）
     * @return 匹配的项目名称，如果没有匹配的项目则返回null
     */
    public String matchNearestProject(Long checkinLat, Long checkinLng) throws Exception {
        if (checkinLat == null || checkinLng == null) {
            log.debug("打卡经纬度为空，无法进行项目匹配");
            return null;
        }
        
        // 转换为实际经纬度
        double actualLat = checkinLat / 1000000.0;
        double actualLng = checkinLng / 1000000.0;
        
        log.info("开始匹配项目，打卡位置: 纬度={}, 经度={}", actualLat, actualLng);
        
        List<ProjectLocation> projectLocations = getAllProjectLocations();
        log.info("获取到 {} 个项目位置进行匹配", projectLocations.size());
        
        String matchedProject = null;
        double minDistance = Double.MAX_VALUE;
        ProjectLocation nearestProject = null;
        
        for (ProjectLocation project : projectLocations) {
            double distance = GeoUtils.getDistance(
                actualLat, actualLng, 
                project.getLatitude(), project.getLongitude()
            );
            
            log.info("项目 {} (经纬度: {},{}) 距离: {}米", 
                project.getProjectName(), project.getLatitude(), project.getLongitude(), String.format("%.2f", distance));
            
            if (distance <= DISTANCE_THRESHOLD && distance < minDistance) {
                minDistance = distance;
                matchedProject = project.getProjectName();
                nearestProject = project;
            }
        }
        
        if (matchedProject != null) {
            log.info("匹配成功: 项目 {} (经纬度: {},{})，距离: {}米", 
                matchedProject, nearestProject.getLatitude(), nearestProject.getLongitude(), String.format("%.2f", minDistance));
        } else {
            log.warn("匹配失败: 未找到{}米范围内的项目", DISTANCE_THRESHOLD);
        }
        
        return matchedProject;
    }
    
    /**
     * 解析项目位置信息
     */
    private ProjectLocation parseProjectLocation(Map<String, Object> record) {
        try {
            String projectName = (String) record.get(PROJECT_NAME_FIELD);
            String locationJson = (String) record.get(PROJECT_LOCATION_FIELD);
            
            if (projectName == null || locationJson == null) {
                log.debug("项目名称或位置信息为空，跳过该记录");
                return null;
            }
            
            // 解析位置JSON
            JsonNode locationNode = objectMapper.readTree(locationJson);
            JsonNode wgs84Point = locationNode.get("WGS84Point");
            
            if (wgs84Point == null) {
                log.debug("项目 {} 缺少WGS84Point信息，跳过", projectName);
                return null;
            }
            
            double latitude = wgs84Point.get("lat").asDouble();
            double longitude = wgs84Point.get("lng").asDouble();
            
            log.debug("解析项目位置: {} - 纬度={}, 经度={}", projectName, latitude, longitude);
            
            return new ProjectLocation(projectName, latitude, longitude);
            
        } catch (JsonProcessingException e) {
            log.warn("解析项目位置信息失败: {}", e.getMessage());
            return null;
        } catch (Exception e) {
            log.warn("处理项目位置记录时发生异常: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 解析氚云API返回的数据
     */
    @SuppressWarnings("unchecked")
    private List<Map<String, Object>> parseResponseData(Object returnData) {
        if (returnData == null) {
            return new ArrayList<>();
        }
        
        if (returnData instanceof List) {
            return (List<Map<String, Object>>) returnData;
        } else if (returnData instanceof Map) {
            Map<String, Object> dataMap = (Map<String, Object>) returnData;
            
            // 检查是否是单个BizObject
            Object bizObject = dataMap.get("BizObject");
            if (bizObject instanceof Map) {
                List<Map<String, Object>> dataList = new ArrayList<>();
                dataList.add((Map<String, Object>) bizObject);
                return dataList;
            }
            
            // 检查BizObjectArray
            Object bizObjectArray = dataMap.get("BizObjectArray");
            if (bizObjectArray instanceof List) {
                return (List<Map<String, Object>>) bizObjectArray;
            }
        }
        
        log.warn("无法解析氚云返回数据格式: {}", returnData.getClass().getSimpleName());
        return new ArrayList<>();
    }
}